﻿#pragma once

#include <chrono>
#include <functional>
#include <iostream>
#include <learn/utils/generator.h>

namespace xi
{

namespace alg
{

template <typename T> struct Alg_Iterator
{
    using return_type = utils::Generator<T>;

    /**
     * @brief 迭代器生成器 
     * 
     * @tparam Preserve 
     * @tparam Log 
     * @return std::function<return_type(std::size_t)> 
     */
    template <bool Preserve = false, bool Log = false> std::function<return_type(std::size_t)> generate()
    {
        return [this](std::size_t n) -> return_type {
            init();
            while (should_continue() && n-- > 0)
            {
                int64_t t = now();
                if constexpr (Preserve)
                    co_yield next_preserve();
                else
                    co_yield next();

                if constexpr (Log)
                    std::cout << "next() -> " << (now() - t) << "ms" << std::endl;
            }
            finish();
        };
    }

  protected:
    virtual T next() = 0;

    // 初始化接口
    virtual void init()
    {
    }

    // 结束接口
    virtual void finish()
    {
    }

    // 迭代并保留之前的值
    virtual T next_preserve()
    {
        return T{};
    }

    // 用于终止条件
    virtual bool should_continue()
    {
        return true;
    }

    /**
     * @brief 获得当前时间
     *
     * @return int64_t
     */
    static int64_t now()
    {
        return std::chrono::duration_cast<std::chrono::milliseconds>(
                   std::chrono::system_clock::now().time_since_epoch())
            .count();
    }
};

} // namespace alg

} // namespace xi